package com.cqfae.deploycentral.app.services.impl;

import com.cqfae.deploycentral.api.utils.IdGenerator;
import com.cqfae.deploycentral.app.base.BaseConstantCode;
import com.cqfae.deploycentral.app.config.FilePathInfo;
import com.cqfae.deploycentral.app.config.PinganGwInfo;
import com.cqfae.deploycentral.app.dao.entity.*;
import com.cqfae.deploycentral.app.dao.mapper.*;
import com.cqfae.deploycentral.app.services.*;
import com.cqfae.deploycentral.app.utils.ConvertUtil;
import com.cqfae.deploycentral.app.utils.GsonUtils;
import com.cqfae.deploycentral.app.utils.NullUtil;
import com.cqfae.deploycentral.app.web.request.ApproveDocumentRequest;
import com.cqfae.deploycentral.app.web.request.ApproverRequest;
import com.cqfae.deploycentral.app.web.request.PinganGwRequest;
import com.cqfae.deploycentral.app.web.request.ReportInfoRequest;
import com.cqfae.deploycentral.app.web.response.IPage;
import com.cqfae.deploycentral.app.web.response.MailResponse;
import com.cqfae.deploycentral.app.web.vo.ApproveFilesVo;
import com.cqfae.deploycentral.app.web.vo.ApproveInfoVo;
import com.cqfae.deploycentral.app.web.vo.SelectedVo;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.google.gson.reflect.TypeToken;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import tk.mybatis.mapper.entity.Example;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;

import static com.cqfae.deploycentral.app.base.BaseConstantCode.*;
import static org.springframework.util.Assert.isTrue;

@Service
@Transactional
public class ApproveDocumentServiceImpl implements ApproveDocumentService {

    private static Logger logger = LoggerFactory.getLogger(ApproveDocumentServiceImpl.class);

    @Autowired
    private IdGenerator idGenerator;
    @Autowired
    private FilePathInfo filePathInfo;
    @Autowired
    private PinganGwInfo pinganGwInfo;
    @Autowired
    private RemoteService remoteService;
    @Autowired
    private ConvertUtil convertUtil;

    @Autowired
    private ExpectPublishEnqueueService expectPublishEnqueueService;
    @Autowired
    private ReportInfoService reportInfoService;
    @Autowired
    private ReportInfoMapper reportInfoMapper;
    @Autowired
    private ApproveDocumentMapper approveDocumentMapper;
    @Autowired
    private ApproveAttachmentMapper approveAttachmentMapper;
    @Autowired
    private ReportTestLinkMapper reportTestLinkMapper;
    @Autowired
    private ConstantsCodeService constantsCodeService;
    @Autowired
    private ExpectPublishEnqueueMapper expectPublishEnqueueMapper;

    //排序条件
    private static final String SQL_ORDER = "ONLINE_TIME DESC";
    //增加文件层级
    private static final String UPLOADDIR = "/uploadFiles/";
    //查询条件
    private static final String ONLINETIME = "onlineTime";
    //评审状态
    private static final String APPROVE_STATUS = "approveStatus";
    //编辑后作废的信息
    private static final String NOUSE = "no_use";
    //邮件分支判断标志
    private static final int INSERT_SCCUESS = 1;
    private static final int UPDATE_SCCUESS = 2;
    private static final int EXCUTE_FLASE = 0;

    @Override
    public List<SelectedVo> handReportSelected(ReportInfoRequest request) {
        List<SelectedVo> expectSelected = new CopyOnWriteArrayList<>();
        List<SelectedVo> selectedVos = getReportSelected(request);
        //若果不同意的话就释放该测试报告资源，允许其他人使用
        Example example = new Example(ApproveDocument.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andNotEqualTo(APPROVE_STATUS,APPROVE_STATUS_FAIL_CODE);
        List<ApproveDocument> approveDocumentList = approveDocumentMapper.selectByExample(example);
        if (selectedVos.isEmpty() || approveDocumentList.isEmpty()) {
            return selectedVos;
        }
        if (!approveDocumentList.isEmpty() && !selectedVos.isEmpty()) {
            List<String> forbidReportCodeList = new CopyOnWriteArrayList<>();
            for (ApproveDocument approveDocument : approveDocumentList) {
                forbidReportCodeList.add(approveDocument.getAppId().toString());
            }
            for (SelectedVo selectedVo : selectedVos) {
                if (!forbidReportCodeList.contains(selectedVo.getCode())) {
                    expectSelected.add(selectedVo);
                }
            }
            return expectSelected;
        }
        return selectedVos;
    }

    /**
     * 查询测试报告的方法：过滤已经被占用的报告
     * @param request
     * @return
     */
    public List<SelectedVo> getReportSelected(ReportInfoRequest request) {
        Example example = new Example(ReportInfo.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andNotEqualTo("reportStatus", BaseConstantCode.REPORT_STATUS_OCCUPY);
        if (StringUtils.isNotBlank(request.getQuery())) {
            criteria.andLike("title", "%" + request.getQuery() + "%");
        }
        List<ReportInfo> reportInfoList = reportInfoMapper.selectByExample(example);
        List<SelectedVo> selectedList = new ArrayList<>();
        for (ReportInfo info : reportInfoList) {
            SelectedVo vo = new SelectedVo(info.getReportCode(), info.getTitle());
            selectedList.add(vo);
        }
        return selectedList;
    }

    /**
     * 查询所有信息（带分页）
     *
     * @return IPage<ApproveDocument>
     */
    @Override
    public IPage<ApproveDocument> dispalyWhitPage(ApproveDocumentRequest request, String type) {
        Page<ApproveDocument> page = PageHelper.startPage(request.getPageNum(), request.getPageSize());
        Example example = new Example(ApproveDocument.class);
        Example.Criteria ca = example.createCriteria();
        example.setOrderByClause(SQL_ORDER);
        logger.info("=========== This dispalyWhitPage's request ============", request);
        if (NullUtil.isNotEmpty(request.getJiraVersionName())) {
            ca.andLike("jiraVersionName", "%" + request.getJiraVersionName() + "%");
        }
        if (NullUtil.isNotEmpty(request.getOnlineTimeStar()) && NullUtil.isNotEmpty(request.getOnlineTimeEnd())) {
            ca.andGreaterThanOrEqualTo(ONLINETIME, request.getOnlineTimeStar())
                    .andLessThanOrEqualTo(ONLINETIME, request.getOnlineTimeEnd());
        }
        if (NullUtil.isNotEmpty(request.getApproveStatus())) {
            ca.andEqualTo(APPROVE_STATUS, request.getApproveStatus());
        }
        String userName = "123";
        if ("develop".equals(type) && NullUtil.isNotEmpty(userName)) {
            ca.andEqualTo("createBy", userName);
        }
        approveDocumentMapper.selectByExample(example);
        IPage<ApproveDocument> ipage = ConvertUtil.pageToIpage(page, new IPage<ApproveDocument>());
        List<ApproveDocument> result = GsonUtils.getInstance()
                .fromJson(GsonUtils.getInstance().toJson(page), new TypeToken<List<ApproveDocument>>() {
                }.getType());
        ipage.setResult(result);
        logger.info("=========== This dispalyWhitPage's result ============", result);
        return ipage;
    }

    /**
     * 需要处理的项目信息的条数
     *
     * @return Integer
     */
    @Override
    public int readedNumber() {
        ApproveDocument aproveDocument = new ApproveDocument();
        aproveDocument.setApproveStatus(APPROVE_STATUS_UNTREATED_CODE);
        return approveDocumentMapper.selectCount(aproveDocument);
    }

    /**
     * 查询单个信息
     *
     * @return ApproveDocument
     */
    @Override
    public ApproveInfoVo getInfoByApprovedId(ApproveDocumentRequest request) {
        //返回视图层的VO
        ApproveInfoVo approveInfoVo = new ApproveInfoVo();
        //根据主键来查询审批文件信息
        ApproveDocument approveDocument = new ApproveDocument();
        approveDocument.setId(request.getId());
        approveDocument = approveDocumentMapper.selectOne(approveDocument);
        //复制表中的信息到Vo
        if (approveDocument.getApproveStatus() != APPROVE_STATUS_FAIL_CODE) {
            approveDocument.setRefuseInfo("");
        }
        BeanUtils.copyProperties(approveDocument, approveInfoVo);
        approveInfoVo.setCode(approveDocument.getJiraVersionId());
        approveInfoVo.setName(approveDocument.getJiraVersionName());
        //根据审批文件的主键来审批附件的信息
        ApproveAttachment approveAttachment = new ApproveAttachment();
        approveAttachment.setApproveId(request.getId());
        List<ApproveAttachment> approveInfoVoList = approveAttachmentMapper.select(approveAttachment);
        approveInfoVo.setAttachmentList(approveInfoVoList);

        getPluginInfo(approveDocument,approveInfoVo);
        return approveInfoVo;
    }
    //Service To:getInfoByApprovedId
    public ApproveInfoVo getPluginInfo(ApproveDocument approveDocument,ApproveInfoVo approveInfoVo){
        //关于插件状态的判断：0.测试报告创建成功（天然支持）；1.评审通过；2.提交至待发布；3.发布成功
        ExpectPublishEnqueue enqueue = new ExpectPublishEnqueue();
        enqueue.setReportCode(approveDocument.getAppId().toString());
        enqueue = expectPublishEnqueueMapper.selectOne(enqueue);

        String approveFirstDone = constantsCodeService.getNameByCode("flow.approveFirstDone");
        String reportFirstDone = constantsCodeService.getNameByCode("flow.reportFirstDone");
        String flag = getFlag(approveDocument);

        if (NullUtil.isEmpty(enqueue) || NOUSE.equals(flag)) {
            approveInfoVo.setPluginStatus("-1");
            approveInfoVo.setPluginDescribe(reportFirstDone);
        } else if (Integer.toString(SCHEDULED_EXEC_SUCCESS).equals(enqueue.getReserved1())) {
            approveInfoVo.setPluginStatus("3");
            approveInfoVo.setPluginDescribe(reportFirstDone);
        } else if (Integer.toString(REPORT_STATUS_WPUBLISH).equals(enqueue.getTestStatus())
                && APPROVE_STATUS_SUCCESS_CODE == enqueue.getApproveStatus()) {
            approveInfoVo.setPluginStatus("2");
            approveInfoVo.setPluginDescribe(reportFirstDone);
        } else if (APPROVE_STATUS_SUCCESS_CODE == enqueue.getApproveStatus()) {
            approveInfoVo.setPluginStatus("1");
            approveInfoVo.setPluginDescribe(approveFirstDone);
        } else if (Integer.toString(REPORT_STATUS_WPUBLISH).equals(enqueue.getTestStatus())){
            approveInfoVo.setPluginStatus("1");
            approveInfoVo.setPluginDescribe(reportFirstDone);
        }else{
            approveInfoVo.setPluginStatus("0");
            approveInfoVo.setPluginDescribe(reportFirstDone);
        }
        return  approveInfoVo;
    }
    //Service to:getPluginInfo
    public String getFlag(ApproveDocument approveDocument){
        String flag = NOUSE;
        ReportTestLink reportTestLink = new ReportTestLink();
        reportTestLink.setVersionId(approveDocument.getJiraVersionId());
        List<ReportTestLink> reportTestLinks = reportTestLinkMapper.select(reportTestLink);
        if(!reportTestLinks.isEmpty()){
            for(ReportTestLink reportTestLinkInfo:reportTestLinks){
                if(!NOUSE.equals(reportTestLinkInfo.getReportCode())){
                    flag = reportTestLink.getReportCode();
                }
            }
        }
        return flag;
    }

    /**
     * 新增文件信息
     * @return INT
     */
    @Override
    public int save(ApproveInfoVo vo) {
        checkIsExistJiraVersionId(vo.getCode());

        ApproveDocument approveDocument = new ApproveDocument();
        Long code = vo.getCode();
        String name = vo.getName();
        BeanUtils.copyProperties(vo, approveDocument);
        //审批主键ID-->附件表/审批表
        Long approveId = idGenerator.nextId();
        //项目基本信息
        approveDocument.setId(approveId);
        //审批状态-新增信息的审批状态全部为2.待审批
        approveDocument.setApproveStatus(APPROVE_STATUS_UNTREATED_CODE);
        //测试报告的信息
        approveDocument = packReportInfo(code,approveDocument);
        //JIRA版本的相关信息
        approveDocument.setJiraVersionId(code);
        approveDocument.setJiraVersionName(name);
        //提交人信息
        if (NullUtil.isNotEmpty(vo.getCommitBy())) {
            approveDocument.setCommitBy(vo.getCommitBy());
            approveDocument.setCreateBy("123");
        } else {
            approveDocument.setCommitBy("123");
            approveDocument.setCreateBy("123");
        }
        approveDocument.setCreateTime(new Date());
        //主文档附件名称
        approveDocument.setApproveDecument(vo.getApproveDecumentAllName());


        inserApproveAttachment(approveId, vo.getAttachmentList());

        int flag = approveDocumentMapper.insert(approveDocument);
        if (flag == INSERT_SCCUESS) {
            sentEmail(approveDocument, INSERT_SCCUESS);
            return INSERT_SCCUESS;
        } else {
            return EXCUTE_FLASE;
        }
    }

    /**
     * 修改审批信息(发邮件)
     * Email
     */
    @Override
    public int updateApprove(ApproverRequest request) {
        if (NullUtil.isNotEmpty(request.getId()) && NullUtil.isNotEmpty(request.getApproverStatus())) {
            ApproveDocument approveDocument = new ApproveDocument();
            approveDocument.setId(request.getId());
            approveDocument = approveDocumentMapper.selectOne(approveDocument);
            if (NullUtil.isEmpty(approveDocument)) {
                isTrue(false, "所传主键有误");
            } else {
                approveDocument.setApprover("123");
                approveDocument.setUpdateBy("123");
                approveDocument.setApproveTime(new Date());
                approveDocument.setUpdateTime(new Date());
                if (NullUtil.isNotEmpty(request.getRefuseInfo())) {
                    approveDocument.setRefuseInfo(request.getRefuseInfo());
                }
                approveDocument.setApproveStatus(request.getApproverStatus());
                approveDocumentMapper.updateByPrimaryKeySelective(approveDocument);
                sentEmail(approveDocument, UPDATE_SCCUESS);
                inserApproveAttachment(request.getId(), request.getAttachmentList());
                return UPDATE_SCCUESS;
            }
        } else {
            isTrue(false, "未传入审批主键值或审批状态，审批失败");
        }
        return EXCUTE_FLASE;
    }

    /**
     * 提交评审和评审时对于附件的新增问题
     * @param approveId
     * @param attachmentList
     */
    public void inserApproveAttachment(Long approveId, List<ApproveAttachment> attachmentList) {
        //Step1 首先确保附件的集合不为空，否则无意义
        if(!attachmentList.isEmpty()){
            for (ApproveAttachment attachment : attachmentList) {
        //Step2 修改时附件id若存在说明此次修改该附件已经上传过，无须新增
                if(NullUtil.isNotEmpty(attachment.getId())
                        && NullUtil.isEmpty(approveAttachmentMapper.selectByPrimaryKey(attachment.getId()))){
                    attachment.setApproveId(approveId);
                    attachment.setAttachmentSuffix(
                            attachment.getAttachmentName().substring(attachment.getAttachmentName().lastIndexOf('.') + 1));
                    attachment.setCreateBy("123");
                    attachment.setCreateTime(new Date());
                    approveAttachmentMapper.insert(attachment);
                }
            }
        }
    }

    /**
     * 重新上传评审文件（修改非评审结果相关信息）
     * Email
     */
    @Override
    public int updateApproveDecumentInfo(ApproveInfoVo vo) {
        //Pre 是否已经存在jira信息
        checkIsExistJiraVersionId(vo.getCode());

        ApproveDocument approveDocument = new ApproveDocument();
        BeanUtils.copyProperties(vo, approveDocument);
        approveDocument = packReportInfo(vo.getCode(),approveDocument);
        //JIRA版本的相关信息
        approveDocument.setJiraVersionId(vo.getCode());
        approveDocument.setJiraVersionName(vo.getName());
        //其它
        approveDocument.setApproveDecument(vo.getApproveDecumentAllName());
        approveDocument.setUpdateBy("123");
        approveDocument.setUpdateTime(new Date());
        approveDocument.setApproveStatus(APPROVE_STATUS_UNTREATED_CODE);
        approveDocument.setApproveTime(new Date());
        //附件新增
        for (ApproveAttachment attachment : vo.getAttachmentList()) {
            //若果已经存在（没有做任何修改就不走新增）
            ApproveAttachment flag = approveAttachmentMapper.selectByPrimaryKey(attachment.getId());
            if (NullUtil.isEmpty(flag)
                    && NullUtil.isNotEmpty(attachment.getId())
                    && NullUtil.isNotEmpty(attachment.getAttachmentName())
                    && NullUtil.isNotEmpty(attachment.getAttachmentPath())) {
                attachment.setApproveId(vo.getId());
                attachment.setAttachmentSuffix(attachment.getAttachmentName()
                        .substring(attachment.getAttachmentName().lastIndexOf('.') + 1));
                attachment.setCreateBy("123");
                attachment.setCreateTime(new Date());
                approveAttachmentMapper.insert(attachment);
            }
        }
        sentEmail(approveDocument, INSERT_SCCUESS);
        return approveDocumentMapper.updateByPrimaryKeySelective(approveDocument);
    }
    //Server to---> save And update
    public void checkIsExistJiraVersionId(Long code){
        Example example = new Example(ApproveDocument.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("jiraVersionId", code);
        criteria.andNotEqualTo(APPROVE_STATUS,APPROVE_STATUS_FAIL_CODE);
        List<ApproveDocument> approveDocuments = approveDocumentMapper.selectByExample(example);

        StringBuilder takerName = new StringBuilder();
        String takerNameString = "";
        if(!approveDocuments.isEmpty()) {
            for(ApproveDocument approveDocument:approveDocuments){
                takerName.append(approveDocument.getCreateBy()+",");
            }
            if(NullUtil.isNotNull(takerName)){
                takerNameString = takerName.toString().substring(0,takerName.length()-1);
            }
            isTrue(false, "该版本已被"+takerNameString+"占用，请核实后再次编辑");
        }
    }
    /**
     * 根据jira的版本ID拼接测试报告信息
     * @param jiraVersionId
     * @return
     */
    public ApproveDocument packReportInfo(Long jiraVersionId,ApproveDocument approveDocument){
        //测试报告的信息
        ReportTestLink reportTestLink = new ReportTestLink();
        reportTestLink.setVersionId(jiraVersionId);
        List<ReportTestLink> reportTestLinks = reportTestLinkMapper.select(reportTestLink);
        String reportCode = "0";
        for(ReportTestLink testLink:reportTestLinks){
            reportCode = testLink.getReportCode();
        }
        ReportInfo reportInfo = new ReportInfo();
        reportInfo.setReportCode(reportCode);
        reportInfo = reportInfoMapper.selectOne(reportInfo);
        if(NullUtil.isEmpty(reportInfo)){
            approveDocument.setAppId(idGenerator.nextId());
            approveDocument.setAppName("Unknown");
        }else{
            approveDocument.setAppId(Long.parseLong(reportCode));
            approveDocument.setAppName(reportInfo.getTitle());
        }
        return approveDocument;
    }

    /**
     * 删除文件
     */
    @Override
    public int fileDelete(Long id, String attachmentPath) {
        //删除文件流
        File file = new File(attachmentPath);
        boolean deleteFileFlag = false;
        if (file.exists()) {
            deleteFileFlag = file.delete();
        }
        //删除附件信息
        int deleteAttachFlag = approveAttachmentMapper.deleteByPrimaryKey(id);

        if (deleteFileFlag && deleteAttachFlag == 1) {
            return 1;
        } else {
            return 0;
        }

    }

    /**
     * 根据审批内容进行审批邮件
     */
    public void sentEmail(ApproveDocument approveDocument, int flag) {
        try {
            PinganGwRequest request = new PinganGwRequest();
            if (flag == INSERT_SCCUESS) {
                request.setAddressTo(pinganGwInfo.getAddressTo());
                request.setTitle("【部署中心-有项目待评审】");
                request.setContent(ConvertUtil.getMailContentForNoticApprove(approveDocument));
            }
            if (flag == UPDATE_SCCUESS && NullUtil.isNotEmpty(approveDocument.getApproveStatus())) {
                request.setAddressTo(approveDocument.getCreateBy() + "@pingan.com.cn");
                request.setTitle("【部署中心-项目评审有更新】");
                request.setContent(ConvertUtil.getMailContentForApproveResult(approveDocument));
            }
            MailResponse mailResponse = remoteService.sendMailToTester(pinganGwInfo.getLogSend(), request);
            String mailJson = GsonUtils.getInstance().toJson(mailResponse);

            logger.info("==== Send Mail ===={}", mailJson);
        } catch (Exception e) {
            logger.info("==== Send Mail ===={}", e);
        }

    }

    /**
     * 上传审批文件
     */
    @Override
    public ApproveFilesVo upload(MultipartFile file, String fileSuffix) throws IOException {
        long attachmentId = idGenerator.nextId();
        String fileRealPath = filePathInfo.getPath() + UPLOADDIR + String.valueOf(attachmentId) + '.' + fileSuffix;
        File destFile = new File(fileRealPath);
        FileUtils.copyInputStreamToFile(file.getInputStream(), destFile);
        //添加附件(视图层的一个VO)
        ApproveFilesVo approveFilesVo = new ApproveFilesVo();
        approveFilesVo.setId(attachmentId);
        approveFilesVo.setAttachmentPath(fileRealPath);
        return approveFilesVo;
    }

    /**
     * 下载审批文件或者附件
     */
    @Override
    public void downloadFile(Long id, HttpServletResponse response) {
        ApproveAttachment approveAttachment = new ApproveAttachment();
        approveAttachment.setId(id);
        approveAttachment = approveAttachmentMapper.selectOne(approveAttachment);
        if (NullUtil.isNotEmpty(approveAttachment)) {
            File file = new File(approveAttachment.getAttachmentPath());
            convertUtil.outputResponse(approveAttachment.getAttachmentName(), file, Integer.parseInt(String.valueOf(file.length())), response);
        }
    }

    @Override
    public boolean checkIsExistReportPlan(SelectedVo selectedVo){
        return true;
    }

}